#pragma once
#include "data.hpp"
#include "config.hpp"
#include <string>
#include "httplib.h"
namespace cloud
{

    class service
    {
    private:
        int server_port_;
        std::string server_ip_;
        std::string download_prefix_;
        httplib::Server server_;
        
        static std::string GetEtag(const BackupInfo &info)
        {
            Fileutil fu(info.real_path_);
            std::string ret = fu.Filename();
            ret += "-";
            ret += std::to_string(info.fsize_);
            ret += "-";
            ret += std::to_string(info.mtime_);
            return ret;
        }
        static void download(const httplib::Request &rq, httplib::Response &rs)
        {
            // 1 获取文件信息
            BackupInfo info;
            DataManager *data = DataManager::GetInstance();
            data->GetOnebyurl(rq.path, &info);
            // 2 判断文件是否被压缩
            if (info.flag_ == true) // 文件被压缩
            {
                Fileutil fu(info.pack_path_);
                fu.UnCompress(info.real_path_); // 传入解压文件名
                fu.Remove();
                // 更新文件信息
                info.flag_ = false;
                data->Update(info);
            }

            // 判断是否是断点续传请求
            std::string old_etag;
            bool isRange = false;
            if (rq.has_header("If-Range"))
            {
                old_etag = rq.get_header_value("If-Range");
                if (old_etag == GetEtag(info)) // 是断点续传且文件未被修改
                    isRange = true;
            }
            // 3 读取文件信息给响应
            Fileutil fu(info.real_path_);
            fu.GetContent(&rs.body);
            if (isRange == false)
            {
                // 4 设置响应报头
                rs.set_header("Accept-Ranges", "bytes");
                rs.set_header("Content-Type", "application/octet-stream");
                rs.set_header("Etag", GetEtag(info)); // Etag:
                rs.status == 200;
            }
            else
            {
                // 4 设置响应报头
                rs.set_header("Accept-Ranges", "bytes");
                rs.set_header("Etag", GetEtag(info)); // Etag:
                rs.status == 206;
            }
        }
        static void listshow(const httplib::Request &rq, httplib::Response &rs)
        {
            std::stringstream ss;
            ss << "<html><head><title>Download</title></head><body><h1>Download</h1><table>";
            std::vector<BackupInfo> vb;
            DataManager *data = DataManager::GetInstance();
            // 获取全部文件信息
            data->GetAll(&vb);
            for (auto &e : vb)
            {
                Fileutil fu(e.real_path_);
                ss << "<tr>"
                   << "<td><a href='" << e.url_;
                ss << "'>" << fu.Filename() << "</a></td>";
                time_t time = e.mtime_;
                ss << "<td align='right'> " << ctime(&time) << "</td>";
                ss << "<td align='right'> " << e.fsize_ / 1024 << "k </td>"; // 不能用fu去获取文件属性,因为文件不一定在/backdir下
                
            }
            ss << "</tr> </table></body></html>";
            rs.body = ss.str();
            rs.set_header("Content-Type", "text/html");
            rs.status = 200;
        }
        static void upload(const httplib::Request &rq, httplib::Response &rs)
        {
            auto filename = rq.matches[1];
            if (rq.has_file("file") == false)
            {
                FATAL("no file 错误码: %d 错误消息: %s",errno,strerror(errno));
                return;
            }
            auto file = rq.get_file_value("file");
            std::string name = file.filename;
            Config *cfg = Config::GetInstance();
            std::string realpath = cfg->GetBackfile() + Fileutil(name).Filename();
            Fileutil fu(realpath);
            if (fu.SetContent(file.content) == false)
            {
                FATAL("up load Setcontent err 错误码: %d 错误消息: %s",errno,strerror(errno));
                return;
            }
            // 修改文件管理信息
            BackupInfo info;
            info.NewBackupInfo(realpath);
            DataManager *data = DataManager::GetInstance();
            data->Insert(info);
        }

    public:
        service()
        {
            Config *cfg = Config::GetInstance();
            server_port_ = cfg->GetPort();
            server_ip_ = cfg->GetIp();
            download_prefix_ = cfg->GetDprefix();
        }
        bool RunModel()
        {
            server_.Get("/", listshow);
            std::string down_load = download_prefix_ + "(.*)";
            server_.Get(down_load, download);
            server_.Post("/upload", upload);
            server_.Get("/listshow", listshow);
            server_.listen(server_ip_, server_port_);
            return true;
        }
    };
};